package com.ysu.concurrency.thread.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author 郭辉
 * @className CASDemo
 * @description cas学习 campaareAndSet
 * @date 2022/1/11 16:05
 * @company 海康威视
 */
public class CASDemo {
    public static void main(String[] args) {
//        testCas();
//        testABA();
        resolveABA();
    }

    /**
     * 测试CAS
     * */
    public static void testCas(){
        /**
         * 初始值
         * */
        AtomicInteger atomicInteger = new AtomicInteger(1);

        /**
         * 参数： 期望值 ， 更新值
         * 当达到期望值时，换成更新值
         */
        boolean result = atomicInteger.compareAndSet(1, 2);
        System.out.println(result);
        System.out.println(atomicInteger);
        /**
         * 此时atomicInteger已经改变，所以不再满足期望，所以不再改变
         * */
        result = atomicInteger.compareAndSet(1, 3);
        System.out.println(result);
        System.out.println(atomicInteger);
    }

    /**
     * 演示CAS 的 ABA 问题
     * */
    public static void testABA(){
        /**
         * 初始值
         * */
        AtomicInteger atomicInteger = new AtomicInteger(1);

        new Thread(()->{
            System.out.println(atomicInteger.compareAndSet(1, 3));
            System.out.println("a->"+atomicInteger);
            System.out.println(atomicInteger.compareAndSet(3, 1));
            System.out.println("a->"+atomicInteger);
        }).start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicInteger.compareAndSet(1,6);
            System.out.println("b->"+atomicInteger);
        }).start();
    }

    /**
     * 解决CAS 的 ABA 问题
     * */
    public static void resolveABA(){
        /**
         * 初始值
         * @pam 初始值，初始版本号
         * */
//        AtomicInteger atomicInteger = new AtomicInteger(1);
        AtomicStampedReference<Integer> atomicReference = new AtomicStampedReference<>(1,1);

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(1, 3,
                    atomicReference.getStamp(),atomicReference.getStamp()+1));
            System.out.println("a + 版本号为" + atomicReference.getStamp() +" ->"+atomicReference.getReference());
            System.out.println(atomicReference.compareAndSet(3, 1,
                    atomicReference.getStamp(),atomicReference.getStamp()+1));
            System.out.println("a + 版本号为" + atomicReference.getStamp() + "->"+atomicReference.getReference());
        }).start();

        new Thread(()->{
            int stamp = atomicReference.getStamp();
            System.out.println("b 期望的版本号 "+ stamp);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(1, 6,
                    stamp, stamp + 1));
            System.out.println("b->"+atomicReference.getReference());
        }).start();
    }
}

